/**
 * @file group_order.cpp
 * @brief Brief description of group_order.cpp
 * @author achdu0000@163.com
 * @version 1.0.0
 * @date 2024/07/18
 */
#include "group_order.h"
// ==================================================
// =============== PRE-DECLARE ======================
// ==================================================

LV_IMG_DECLARE(img_logo_100x100)
LV_FONT_DECLARE(lv_font_gb2312_24)
LV_FONT_DECLARE(lv_font_gb2312_14)

// ==================================================
// =============== DEFINATIONS ======================
// ==================================================

#define GROUP_ORDER_OK_COLOR lv_palette_main(LV_PALETTE_LIGHT_GREEN)
#define GROUP_ORDER_NO_COLOR lv_palette_main(LV_PALETTE_RED)

typedef struct
{
    lv_obj_t *text_label;
    lv_obj_t *subtext_label;
    lv_meter_indicator_t *arc_indic;
    lv_color_t arc_indic_color;
    bool is_ordered;
} group_member_t;

// ==================================================
// =============== STATIC VARIABLES =================
// ==================================================

static lv_obj_t *order_meter;
static lv_coord_t meter_width;
static lv_coord_t meter_height;
static lv_obj_t *btn;

static lv_style_t text_style;
static lv_style_t subtext_style;

static group_member_t member[] = {
    {.text_label = nullptr,
     .subtext_label = nullptr,
     .arc_indic = nullptr,
     .arc_indic_color = lv_palette_main(LV_PALETTE_PURPLE), /* color of group order */
     .is_ordered = false},
    {.text_label = nullptr,
     .subtext_label = nullptr,
     .arc_indic = nullptr,
     .arc_indic_color = lv_palette_main(LV_PALETTE_AMBER), /* color of requirements specialist order */
     .is_ordered = false},
    {.text_label = nullptr,
     .subtext_label = nullptr,
     .arc_indic = nullptr,
     .arc_indic_color = lv_palette_main(LV_PALETTE_CYAN), /* color of weekly logger */
     .is_ordered = false},
    {.text_label = nullptr,
     .subtext_label = nullptr,
     .arc_indic = nullptr,
     .arc_indic_color = lv_palette_main(LV_PALETTE_YELLOW), /* color of leader order */
     .is_ordered = false},
    {.text_label = nullptr,
     .subtext_label = nullptr,
     .arc_indic = nullptr,
     .arc_indic_color = lv_palette_main(LV_PALETTE_BLUE), /* color of quality inspector */
     .is_ordered = false},
    {.text_label = nullptr,
     .subtext_label = nullptr,
     .arc_indic = nullptr,
     .arc_indic_color = lv_palette_main(LV_PALETTE_ORANGE), /* color of presenter */
     .is_ordered = false},
};

static uint8_t order_i = 0;

static uint8_t order_count = 0;

// ==================================================
// =============== STATIC FUNCTION ==================
// ==================================================

/**
 * init the text style and sub text style
 */
static void init_styles();

/**
 * init meter and its arc indicator
 */
static void init_meter_and_indic(lv_obj_t *parent);

/**
 * init labels
 */
static void init_label(lv_obj_t *parent);

/**
 * init btn for click
 */
static void init_btn(lv_obj_t *parent);

/**
 * init the white lines as border
 */
static void init_lines(lv_obj_t *parent);

/**
 * used for the btn clicked events
 */
static void group_order_cb(lv_event_t *e);

/**
 * used for order
 */
static void order_cb(lv_event_t *e);

/**
 * calc for the current sector to order
 */
static uint8_t get_order_sector(lv_coord_t x, lv_coord_t y);

/**
 * goto senior part when junior part (group order) has been finished
 */
static void goto_senior_part();

// ==================================================
// =============== IMPLEMENTATION ===================
// ==================================================

static void init_styles()
{
    lv_style_init(&text_style);
    lv_style_set_text_font(&text_style, &lv_font_gb2312_24);
    lv_style_set_text_align(&text_style, LV_TEXT_ALIGN_CENTER);
    lv_style_set_text_color(&text_style, lv_color_white());

    lv_style_init(&subtext_style);
    lv_style_set_text_font(&subtext_style, &lv_font_gb2312_14);
    lv_style_set_text_align(&subtext_style, LV_TEXT_ALIGN_CENTER);
    lv_style_set_text_color(&subtext_style, lv_color_white());
    lv_style_set_border_color(&subtext_style, lv_color_white());
    lv_style_set_border_width(&subtext_style, 1);
}

static void init_meter_and_indic(lv_obj_t *parent)
{
    order_meter = lv_meter_create(parent);

    /* remove the background and the circle from the middle */
    lv_obj_remove_style(order_meter, NULL, LV_PART_MAIN);
    lv_obj_remove_style(order_meter, NULL, LV_PART_INDICATOR);

    lv_obj_set_size(order_meter, meter_width, meter_height);
    lv_obj_center(order_meter);

    lv_meter_scale_t *scale = lv_meter_add_scale(order_meter);
    lv_meter_set_scale_ticks(order_meter, scale, 6, 0, 0, lv_color_black());
    lv_meter_set_scale_range(order_meter, scale, 0, 6, 360, 240);

    uint16_t arc_indic_width = meter_width / 2;
    for (uint8_t i = 0; i < 6; i++)
    {
        member[i].arc_indic = lv_meter_add_arc(order_meter, scale, arc_indic_width, member[i].arc_indic_color, 0);
        lv_meter_set_indicator_start_value(order_meter, member[i].arc_indic, i);
        lv_meter_set_indicator_end_value(order_meter, member[i].arc_indic, i + 1);
    }
}

static void init_label(lv_obj_t *parent)
{
    /* the offset(radius) between main label and circle center */
    lv_coord_t ofs_r = 150;

    /* common config of labels */
    for (uint8_t i = 0; i < 6; i++)
    {
        /* create main label */
        member[i].text_label = lv_label_create(parent);
        lv_obj_add_style(member[i].text_label, &text_style, LV_PART_MAIN | LV_STATE_DEFAULT);

        /* create sub label */
        member[i].subtext_label = lv_label_create(parent);
        lv_obj_add_style(member[i].subtext_label, &subtext_style, LV_PART_MAIN | LV_STATE_DEFAULT);
        /* hidden oorder info as default */
        if (i != 0)
            lv_obj_add_flag(member[i].subtext_label, LV_OBJ_FLAG_HIDDEN);
    }

    /* title label for group No. */
    lv_label_set_text(member[0].text_label, "G20体联\n·浅度课设·\n群组点名");
    lv_obj_align(member[0].text_label, LV_ALIGN_CENTER, 0, -ofs_r);
    /* sub title label for some tips */
    lv_label_set_text(member[0].subtext_label, "长 按 签 到\n短 按 未 到");
    lv_obj_align_to(member[0].subtext_label, member[0].text_label, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);

    /*
     *    |-`x`-|  _
     *    |     /  |
     *    |    /r  |
     *    |`θ`/_  `y`
     *    |  /s    |
     *    | /f     |
     *    |/o      _
     */
    lv_coord_t ofs_r_sin = ofs_r * lv_trigo_sin(60) / LV_TRIGO_SIN_MAX;
    lv_coord_t ofs_r_cos = ofs_r * lv_trigo_cos(60) / LV_TRIGO_SIN_MAX;

    /* order label for requirements specialist */
    lv_label_set_text(member[1].text_label, "【需求员】\n南二开");
    lv_obj_align(member[1].text_label, LV_ALIGN_CENTER, ofs_r_sin, -ofs_r_cos);

    /* order label for weekly logger */
    lv_label_set_text(member[2].text_label, "【周志员】\n南三开");
    lv_obj_align(member[2].text_label, LV_ALIGN_CENTER, ofs_r_sin, ofs_r_cos);

    /* order label for leader */
    lv_label_set_text(member[3].text_label, "【组 长】\n南大开");
    lv_obj_align(member[3].text_label, LV_ALIGN_CENTER, 0, ofs_r);

    /* order label for quality inspector */
    lv_label_set_text(member[4].text_label, "【优裁员】\n南四开");
    lv_obj_align(member[4].text_label, LV_ALIGN_CENTER, -ofs_r_sin, ofs_r_cos);

    /* create order label for presenter */
    lv_label_set_text(member[5].text_label, "【展示员】\n南五开");
    lv_obj_align(member[5].text_label, LV_ALIGN_CENTER, -ofs_r_sin, -ofs_r_cos);
}

static void init_btn(lv_obj_t *parent)
{
    btn = lv_btn_create(parent);
    lv_obj_set_size(btn, 100, 100);
    lv_obj_set_style_radius(btn, LV_RADIUS_CIRCLE, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_color(btn, lv_color_white(), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_img_src(btn, &img_logo_100x100, LV_PART_MAIN);
    lv_obj_center(btn);

    lv_obj_add_event_cb(btn, (lv_event_cb_t)group_order_cb, LV_EVENT_SHORT_CLICKED, nullptr);
    lv_obj_add_event_cb(btn, (lv_event_cb_t)group_order_cb, LV_EVENT_LONG_PRESSED, nullptr);
}

static void init_lines(lv_obj_t *parent)
{
    lv_coord_t r = LV_MIN(meter_height, meter_width) / 2;
    lv_coord_t r_sin30 = r / 2;
    /* sqrt(3)/2 = 0.8660... */
    lv_coord_t r_cos30 = (lv_coord_t)(r * 0.866f);

    /* for three lines */
    static lv_point_t points[6];

    points[0].x = 0;
    points[0].y = r;
    points[1].x = 2 * r;
    points[1].y = r;

    points[2].x = r + r_sin30;
    points[2].y = r - r_cos30;
    points[3].x = r - r_sin30;
    points[3].y = r + r_cos30;

    points[4].x = points[3].x;
    points[4].y = points[2].y;
    points[5].x = points[2].x;
    points[5].y = points[3].y;

    for (uint8_t i = 0; i < 3; i++)
    {
        lv_obj_t *line = lv_line_create(parent);
        lv_line_set_points(line, points + i * 2, 2);
        lv_obj_set_style_line_color(line, lv_color_white(), LV_PART_MAIN | LV_STATE_DEFAULT);
        lv_obj_set_style_line_width(line, 3, LV_PART_MAIN | LV_STATE_DEFAULT);
    }
}

static void group_order_cb(lv_event_t *e)
{
    lv_event_code_t code = lv_event_get_code(e);

    if (code != LV_EVENT_SHORT_CLICKED && code != LV_EVENT_LONG_PRESSED && code != LV_EVENT_RELEASED)
        return;

    if (order_i == 0xff) /* all parts have benn ordered */
    {
        goto_senior_part();
    }
    else /* still need to order */
    {
        if (order_i == 5)
        {
            /*
             * order_i == 5
             * means group order has been finished, change the btn to show some tip infos for goto senior part of out design
             */

            lv_obj_t *btn = lv_event_get_target(e);
            lv_obj_t *btn_parent = lv_obj_get_parent(btn);
            lv_obj_del(btn);
            btn = lv_btn_create(btn_parent);
            lv_obj_center(btn);

            lv_obj_t *label = lv_label_create(btn);
            lv_label_set_text(label, "扶好坐稳\n进入深度课设");
            lv_obj_add_style(label, &text_style, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_center(label);

            lv_obj_add_event_cb(btn, (lv_event_cb_t)group_order_cb, LV_EVENT_SHORT_CLICKED, NULL);
            lv_obj_add_event_cb(btn, (lv_event_cb_t)group_order_cb, LV_EVENT_LONG_PRESSED, NULL);

            order_i = 0xff;
        }
    }
}

static void goto_senior_part()
{
    LV_LOG_INFO("goto_senior_part()");
#ifdef SENIOR_PART_OF_DESIGN
    switch_to_senior_part();
#endif
}

static void order_cb(lv_event_t *e)
{
    lv_event_code_t code = lv_event_get_code(e);
    if (code == LV_EVENT_SHORT_CLICKED || code == LV_EVENT_LONG_PRESSED)
    {
        lv_indev_t *indev = lv_indev_get_act();
        lv_point_t point;
        if (indev)
        {
            lv_indev_get_point(indev, &point);

            char buf[128];
            lv_snprintf(buf, sizeof(buf), "p_x = %d, p_y = %d", point.x, point.y);
            LV_LOG_INFO(buf);

            uint8_t sector_index = get_order_sector(point.x, point.y);

            if (sector_index != 0 && !member[sector_index].is_ordered)
            {
                member[sector_index].arc_indic->type_data.arc.color = (code == LV_EVENT_LONG_PRESSED) ? GROUP_ORDER_OK_COLOR : GROUP_ORDER_NO_COLOR;
                /* remove hidden flag */
                lv_obj_clear_flag(member[sector_index].subtext_label, LV_OBJ_FLAG_HIDDEN);
                lv_label_set_text(member[sector_index].subtext_label, (code == LV_EVENT_LONG_PRESSED) ? "√已签到√" : "×未签到×");
                lv_obj_align_to(member[sector_index].subtext_label, member[sector_index].text_label, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
                member[sector_index].is_ordered = true;
                order_count++;
            }
            if (order_count == 5)
            {
                order_i = 5;
                lv_event_send(btn, LV_EVENT_SHORT_CLICKED, nullptr);
            }
        }
    }
}

static uint8_t get_order_sector(lv_coord_t x, lv_coord_t y)
{
    uint8_t sector_index;
    uint8_t quadrant;
    if (x > meter_width / 2)
    {
        quadrant = (y < meter_height / 2 ? 1 : 4);
    }
    else
    {
        quadrant = (y < meter_height / 2 ? 2 : 3);
    }

    lv_coord_t dis_x_sqrt = (x - meter_width / 2) * (x - meter_width / 2);
    lv_coord_t dis_y_sqrt = (y - meter_width / 2) * (y - meter_width / 2);
    lv_coord_t dis_sqrt = dis_x_sqrt + dis_y_sqrt;

    switch (quadrant)
    {
    case 1:
        sector_index = (dis_sqrt > 2 * dis_x_sqrt ? 0 : 1);
        break;
    case 2:
        sector_index = (dis_sqrt > 2 * dis_x_sqrt ? 0 : 5);
        break;
    case 3:
        sector_index = (dis_sqrt > 2 * dis_x_sqrt ? 3 : 4);
        break;
    case 4:
        sector_index = (dis_sqrt > 2 * dis_x_sqrt ? 3 : 2);
        break;
    default:
        break;
    }

    char buf[128];
    lv_snprintf(buf, sizeof(buf), "q = %d, sector_index = %d", quadrant, sector_index);
    LV_LOG_INFO(buf);
    return sector_index;
}

void group_order_on_create(lv_obj_t *parent)
{

    meter_width = lv_obj_get_width(parent);
    meter_height = lv_obj_get_height(parent);

    init_styles();

    init_meter_and_indic(parent);

    init_label(parent);

    init_lines(parent);

    init_btn(parent);

    lv_obj_add_event_cb(order_meter, order_cb, LV_EVENT_ALL, nullptr);
}